/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/system
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AEDateTime.h
// Author:		Gianluca Belardelli
// Date:		07/10/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEDATETIME_H_
#define _AEDATETIME_H_

/// \brief A class representing a time span.
class AE_COREDLLIMPEXP AETimeSpan
{
	friend class AEDateTime;

// Members
private:
	AEINT64 				m_n64TotalNanoSeconds;
	static const AEINT64	ms_n64InfiniteSpan = 0x7fffffffffffffffLL;

public:
	/// \brief Creates an infinitely long time span
	static AETimeSpan Infinite( void );
	
	/// \brief Creates a time span from a given number of days.
	static AETimeSpan FromDays( AEINT64 nDays );
	
	/// \brief Creates a time span from a given number of days.
	static AETimeSpan FromDays( AEDOUBLE64 dDays );
	
	/// \brief Creates a time span from a given number of hours.
	static AETimeSpan FromHours( AEINT64 nHours );
	
	/// \brief Creates a time span from a given number of hours.
	static AETimeSpan FromHours( AEDOUBLE64 dHours );
	
	/// \brief Creates a time span from a given number of minutes.
	static AETimeSpan FromMinutes( AEINT64 nMinutes );
	
	/// \brief Creates a time span from a given number of minutes.
	static AETimeSpan FromMinutes( AEDOUBLE64 dMinutes );
	
	/// \brief Creates a time span from a given number of seconds.
	static AETimeSpan FromSeconds( AEINT64 nSeconds );
	
	/// \brief Creates a time span from a given number of seconds.
	static AETimeSpan FromSeconds( AEDOUBLE64 dSeconds );
	
	/// \brief Creates a time span from a given number of milliseconds.
	static AETimeSpan FromMilliSeconds( AEINT64 nMilliSeconds );
	
	/// \brief Creates a time span from a given number of milliseconds.
	static AETimeSpan FromMilliSeconds( AEDOUBLE64 dMilliSeconds );
	
	/// \brief Creates a time span from a given number of microseconds.
	static AETimeSpan FromMicroSeconds( AEINT64 nMicroSeconds );
	
	/// \brief Creates a time span from a given number of microseconds.
	static AETimeSpan FromMicroSeconds( AEDOUBLE64 dMicroSeconds );
	
	/// \brief Creates a time span from a given number of nanoseconds.
	static AETimeSpan FromNanoSeconds( AEINT64 nNanoSeconds );
	
	/// \brief Creates a time span from a given number of nanoseconds.
	static AETimeSpan FromNanoSeconds( AEDOUBLE64 dNanoSeconds );
	
	/// \brief Returns the total number of days of the time span.
	AEDOUBLE64 TotalDays( void ) const;
	
	/// \brief Returns the total number of hours of the time span.
	AEDOUBLE64 TotalHours( void ) const;
	
	/// \brief Returns the total number of minutes of the time span.
	AEDOUBLE64 TotalMinutes( void ) const;
	
	/// \brief Returns the total number of seconds of the time span.
	AEDOUBLE64 TotalSeconds( void ) const;
	
	/// \brief Returns the total number of milliseconds of the time span.
	AEDOUBLE64 TotalMilliSeconds( void ) const;
	
	/// \brief Returns the total number of microseconds of the time span.
	AEDOUBLE64 TotalMicroSeconds( void ) const;
	
	/// \brief Returns the total number of nanoseconds of the time span.
	AEDOUBLE64 TotalNanoSeconds( void ) const;
	
	/// \brief Adds two time spans.
	AETimeSpan operator+( const AETimeSpan &tsOther ) const;
	
	/// \brief Increases the time span by another time span.
	AETimeSpan& operator+=( const AETimeSpan &tsOther );
	
	/// \brief Subtracts two time spans.
	AETimeSpan operator-( const AETimeSpan &tsOther ) const;
	
	/// \brief Decreases the time span by another time span.
	AETimeSpan& operator-=( const AETimeSpan &tsOther );
	
	/// \brief Compares two given date times.
	bool operator==( const AETimeSpan &tsOther ) const;
	
	/// \brief Compares two given time spans.
	bool operator!=( const AETimeSpan &tsOther ) const;
	
	/// \brief Compares two given time spans.
	bool operator<=( const AETimeSpan &tsOther ) const;
	
	/// \brief Compares two given time spans.
	bool operator<( const AETimeSpan &tsOther ) const;
	
	/// \brief Compares two given time spans.
	bool operator>=( const AETimeSpan &tsOther ) const;
	
	/// \brief Compares two given time spans.
	bool operator>( const AETimeSpan &tsOther ) const;
};

class AE_COREDLLIMPEXP AEDateTime
{
// Members
private:
	AEINT64					m_n64NanoSecondsSinceEpoch;
	static const AEINT64	ms_n64InvalidTime = 0x8000000000000000LL;

public:
	/// \brief The time zone type.
	enum AETimeZone
	{
		UTC,
		LOCAL
	};

// Methods
public:
	/// \brief Constructs an invalid date time.
	AEDateTime( void );
	
	/// \brief Returns the current time.
	static AEDateTime Now( void );
	
	/// \brief Returns a date time object representing the date 1970-01-01.
	static AEDateTime GetUnixEpoch( void );
	
	/// \brief Retrieves the date of the date time.
	void GetDate( AETimeZone tzTimeZone, AEINT32 &nYear, AEINT32 &nMonth, AEINT32 &nDay ) const;
	
	/// \brief Retrieves the time of the date time.
	void GetTime( AETimeZone tzTimeZone, AEINT32 &nHour, AEINT32 &nMinute, AEINT32 &nSecond ) const;
	
	/// \brief Returns the year of the date time.
	AEINT32 GetYear( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the 1-based month of the date time.
	AEINT32 GetMonth( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the 1-based day of month of the date time.
	AEINT32 GetDayOfMonth( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the hour of the date time.
	AEINT32 GetHour( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the minute of the date time.
	AEINT32 GetMinute( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the second of the date time.
	AEINT32 GetSecond( AETimeZone tzTimeZone ) const;
	
	/// \brief Returns the millisecond of the date time.
	AEINT32 GetMilliSecond( void ) const;
	
	/// \brief Returns the microsecond of the date time.
	AEINT32 GetMicroSecond( void ) const;
	
	/// \brief Returns the nanosecond of the date time.
	AEINT32 GetNanoSecond( void ) const;
	
	/// \brief Stores the date time in a platform-specific native time representation.
	void ToNative( AETIMESTRUCT64 &ttTime ) const;
	
	/// \brief Returns a date time object constructed from a platform-specific native representation.
	static AEDateTime FromNative( AETIMESTRUCT64 ttTime );
	
	/// \brief Adds a time span to the date time.
	AEDateTime operator+( const AETimeSpan &tsSpan ) const;
	
	/// \brief Advances the date time by the given time span.
	AEDateTime &operator+=( const AETimeSpan &tsSpan );
	
	/// \brief Subtracts a time span from the date time.
	AEDateTime operator-( const AETimeSpan &tsSpan ) const;
	
	/// \brief Advances the date time backwards by the given time span.
	AEDateTime &operator-=( const AETimeSpan &tsSpan );
	
	/// \brief Returns the time span between two given date times.
	AETimeSpan operator-( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator==( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator!=( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator<=( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator<( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator>=( const AEDateTime &dtOther ) const;
	
	/// \brief Compares two given date times.
	bool operator>( const AEDateTime &dtOther ) const;
	
	/// \brief Returns true if the object represents a valid date time.
	bool IsValid( void ) const;
	
	/// \brief Formats the date time to a string representation.
	///
	/// \param buffer
	///   A buffer to hold the result.
	///
	/// \param szFormat
	///   A format specifier as defined by the C library function strftime.
	///
	/// \param AETimeZone
	///   Time zone type.
	///
	/// \returns HKV_FAILURE if the passed buffer is too small.
	template<AEINT32 N>
	AEUINT32 Format( char (&buffer)[N], const char *lpFormat, AETimeZone tzTimeZone );
};

#endif // _AEDATETIME_H_
